package com.apes.fn.scm.internal.help.service.voucher.retail;

import com.apes.fn.mdm.paint.PaintBusinessScope;
import com.apes.fn.mdm.paint.PaintBusinessScopeRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailReturn.RetailReturn;
import com.apes.fn.scm.retailReturn.RetailReturnItem;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 服务方案油漆退回
 *      同公司内协实施油漆退货
 * @Author wuq
 * @Date 2021-10-19
 */
@Service
public class ServerPlanPaintReturnVoucherService extends DomainService {

    @Autowired
    private ContractService contractService;
    @Autowired
    private VoucherInventoryRepository voucherInventoryRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PaintBusinessScopeRepository paintBusinessScopeRepository;
    @Autowired
    private ServicePlanItemRepository servicePlanItemRepository;


    public void process( List<RetailReturnItem> retailReturnItems){
        RetailReturn retailReturn = retailReturnItems.get(0).getOrder();

        // 找基地方案，获取到服务门店
        ServicePlanItem basePlanItem = findBaseServicePlanItem(retailReturnItems.get(0).getRetailOrderItem().getOriginnumber());

        // 查询喷漆经营范围，判断是否为对账公司
        List<PaintBusinessScope> paintBusinessScopes =  paintBusinessScopeRepository.findByDept(basePlanItem.getServicePlan().getBelongDept().getId());
        PartyRole paintCompany = paintBusinessScopes.get(0).getCompany();       // 油漆对账公司
        PartyRole supplier = paintBusinessScopes.get(0).getSupplier();          // 油漆供应商

        // 门店退油漆采购
        Voucher originSaleVoucher = voucherRepository.findOne(
                JpaDsl.toCriteriaByEq("sourceBusinessType", RetailOrder.class.getSimpleName(),
                        "source", retailReturn.getSaleOrder().getId(), "origin", retailReturn.getSaleOrder().getId(), "voucherType", "CUSTOMER_SALE"))
                .orElseThrow(() -> new RuntimeException("生成油漆返厂凭证时，未找到：" + retailReturn.getSaleOrder().getId() + " 的业务凭证！"));;

        // 判断是为跨公司，如果是就退油漆对账公司部分
        if (retailReturn.getCompany().getId().equals(paintCompany.getId())) {
            // 同公司退货
            returnPaintPurchaseVoucher(supplier, originSaleVoucher, retailReturn, retailReturnItems);
        } else {
            // 门店退油漆给对账公司
            returnPaintPurchaseVoucher(paintCompany, originSaleVoucher, retailReturn, retailReturnItems);

            // 跨公司退货
            returnCrossPaintVoucher(paintCompany, supplier, retailReturn, retailReturnItems);
        }
    }

    private void returnCrossPaintVoucher(PartyRole paintCompany, PartyRole supplier, RetailReturn retailReturn, List<RetailReturnItem> retailReturnItems){
        // 第一步：退对门店的销售
        PartyRole partner = retailReturn.getCompany().getParty().getPartyRoleByType("Customer");
        String originItemId = retailReturnItems.get(0).getRetailOrderItem().getOriginnumber();    // 原销售明细行
        ServicePlanItem basePlanItem = findBaseServicePlanItem(originItemId);
        Voucher originSaleVoucher = voucherRepository.findSaleVoucherByCompanyAndItemOrigin(paintCompany, partner, basePlanItem.getId());

        returnSaleVoucher(retailReturn, retailReturnItems, originSaleVoucher);

        // 第二步：退对油漆供应商的采购
        returnPaintPurchaseVoucher(supplier, originSaleVoucher, retailReturn, retailReturnItems);
    }

    private void returnPaintPurchaseVoucher(PartyRole supplier, Voucher originSaleVoucher, RetailReturn retailReturn, List<RetailReturnItem> retailReturnItems){
        Voucher voucher = new Voucher();
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.PURCHASE_RETURN);

        voucher.setPartner(supplier.getParty().getPartyRoleByType("Supplier"));
        voucher.setCompany(originSaleVoucher.getCompany());
        voucher.setDept(originSaleVoucher.getDept());
        voucher.setClerk(retailReturn.getClerk());

        Contract contract = contractService.getContract(voucher.getDept(), voucher.getPartner(), "distribution", "supplier", "内协油漆退回业务");
        voucher.setContract(contract);
        voucher.setInventoryMode(contract.getCooperation().getInventoryMode());
        voucher.setAccountingMethod(contract.getCooperation().getAccountingMethod());

        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());

        voucher.setVoucherItems(
                retailReturnItems.stream().map( retailReturnItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    voucherItem.setProduct(retailReturnItem.getProduct());

                    voucherItem.setUom(retailReturnItem.getUom());
                    voucherItem.setProductQty(-1.00 * retailReturnItem.getProductUomQty());
                    voucherItem.setOriginItemId(String.valueOf(retailReturnItem.getId()));
                    voucherItem.setSourceItemId(String.valueOf(retailReturnItem.getId()));
                    voucherItem.setOwner(originSaleVoucher.getCompany());

                    //找到原销售凭证的明细行
                    VoucherItem saleVoucherItem = originSaleVoucher.getVoucherItems().stream()
                            .filter( saleItem -> saleItem.getProduct().getId().equals(retailReturnItem.getProduct().getId()) )
                            .findFirst()
                            .orElseThrow(() -> new RuntimeException("生成油漆返厂凭证时，根据商品编码没有找到对应的凭证明细，" +
                                    "商品编码："+ retailReturnItem.getProduct().getId() +"，凭证编码："+ originSaleVoucher.getId()));

                    // 获取原销售批次
                    VoucherInventory voucherInventory = voucherInventoryRepository.findAll(
                            JpaDsl.toCriteriaByEq("voucher.id", originSaleVoucher.getId(), "voucherItem", saleVoucherItem))
                            .stream().findFirst().get();

                    InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();
                    voucherItem.setInventoryBatch(inventoryBatch);
                    voucherItem.setPriceUnit(inventoryBatch.getTaxCostPrice());
                    voucherItem.setSupplier(inventoryBatch.getSupplier());
                    voucherItem.setTax(inventoryBatch.getTax());

                    //  增加（减少）冻结数量
                    inventoryService.changeFrostQty(inventoryBatch, retailReturnItem.getUom(), retailReturnItem.getProductUomQty(), inventoryBatch.getCompany(),
                            retailReturn.getInnerBusinessType(), retailReturn.getId(), retailReturnItem.getId(), "生成零售油漆服务商品返厂凭证");

                    return voucherItem;
                }).collect(Collectors.toSet()));

        Voucher newVoucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createFixedOriginNumberInvoice(retailReturn, newVoucher);
    }

    /**
     * 构建销售退回凭证
     *
     * @param retailReturn      零售退货主表
     * @param retailReturnItems  零售退货明细
     * @param originSaleVoucher 原销售凭证
     */
    private void returnSaleVoucher(RetailReturn retailReturn, List<RetailReturnItem> retailReturnItems, Voucher originSaleVoucher) {
        Voucher voucher = new Voucher();
        // 销售退回必填字段
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);
        voucher.setVoucher(originSaleVoucher);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company", "partner", "contract");
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式

        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());
        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());

        voucher.setVoucherItems(
                originSaleVoucher.getVoucherItems().stream().map(saleItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    retailReturnItems.stream()
                            .filter(returnItem -> returnItem.getProduct().getId().equals(saleItem.getProduct().getId()))
                            .forEach(retailReturnItem -> {

                                voucherItem.setProduct(saleItem.getProduct());
                                voucherItem.setTax(saleItem.getTax());

                                voucherItem.setUom(saleItem.getUom());          // 设置为销售的单位以及数量
                                voucherItem.setProductQty(-1 * Math.abs(saleItem.getProductQty()));
                                voucherItem.setPriceUnit(saleItem.getPriceUnit());      // 默认为退货单价
                                voucherItem.setOwner(originSaleVoucher.getCompany());

                                voucherItem.setOriginItemId(retailReturnItem.getId());
                                voucherItem.setSourceItemId(retailReturnItem.getId());
                                voucherItem.setVoucherItem(saleItem);   // 退回时传入明细行号
                    });

                    return voucherItem;
                }).collect(Collectors.toSet()));

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        createFixedOriginNumberInvoice(retailReturn, voucher);
    }

    /**
     * 根据门店方案明细查找基地方案明细
     *
     * @param id 门店方案明细编码
     * @return ServicePlanItem
     */
    private ServicePlanItem findBaseServicePlanItem(String id) {
        List<ServicePlanItem> list = servicePlanItemRepository.findAll(
                JpaDsl.toCriteriaByEq("parentServicePlanItem.id", id, "terminationDate", null));
        if (list.size() == 0) throw new RuntimeException(String.format("根据服务方案明细行号[%s]获取基地方案明细行失败！", id));
        if (list.size() > 1) throw new RuntimeException("找到多条子明细行，请检查程序");
        return list.stream().findFirst().get();
    }

    private void createFixedOriginNumberInvoice(RetailReturn retailReturn, Voucher voucher) {
        // 获取 invoice Mapping 文件
        Map m = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));

        m.put("origin", retailReturn.getSaleOrder().getSource());
        m.put("originBusinessType", retailReturn.getSaleOrder().getSourceBusinessType());

        // 生成账单
        invoke("invoice.create", m);
    }
}
